home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 Extra Demos / Platform Scrolling / Platform Scrolling.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-25  |  26.5 KB  |  938 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. // Platform Scrolling.c
  3. //
  4. // By Vern Jensen. Created in September, 1997.
  5. ///--------------------------------------------------------------------------------------
  6.  
  7.  
  8. #include <SWFPSReport.h>
  9. #include <SWIncludes.h>
  10. #include <SWGameUtils.h>
  11. #include <SWApplication.h>
  12.  
  13. #include "Platform Scrolling.h"
  14.  
  15.  
  16. #define    kFullScreenWindow            true        // Toggles between 512x384 and 640x480
  17. #define kWorldRectInset                0            // Make the SpriteWorld smaller?
  18. #define    kInterlacedMode                false        // Turns Interlaced mode on/off
  19. #define kSyncToVBL                    false        // Sync SpriteWorld to VBL?
  20. #define kMaxFPS                        30            // Set to 0 for unrestricted speed
  21.  
  22.  
  23. #define kWalkIncrease                1
  24. #define kMaxWalkSpeed                10
  25. #define kMaxFallSpeed                20
  26. #define kJumpSpeed                    26
  27. #define kMaxSpriteJumpDistance        19        // How many frames the sprite can keep going up
  28. #define kGravitySpeed                2
  29.  
  30. #define kMovingFloorSpeed            0        // How often the moving floors change frames
  31. #define kMovingFloorForce            2        // How far they move the sprite when the move
  32. #define kChangingFloorSpeed            5        // Frame rate of the changing floor
  33. #define kChangingFloorWait            120        // How long of a delay between on/off
  34. #define kSpikeSpeed                    2        // How fast the spikes move
  35. #define    kSpikeChangeDelay            150        // How long they wait between moves
  36. #define    kExitSignSpeed                8        // Animation speed of exit sign
  37. #define    kArrowSpeed                    10        // Animation speed of arrow
  38.  
  39. #define    kRunningCorrection            7        // Determines how many pixel a sprite can fall through
  40.                                             // the top of a tile and still be put back on top.
  41.                                             // Useful for running across tiles with holes inbetween.
  42.  
  43. #define kSpriteMoveDistance            80            // How far the sprite can move from
  44.                                                 // the center of the screen, in pixels.
  45.                                                 // Try making this value higher!
  46.                                                 
  47.  
  48. #define kTileWidth                    40
  49. #define kTileHeight                    40
  50.  
  51.  
  52. #define kStartRow                    5            // Starting position of sprite
  53. #define kStartCol                    5            // in tile col and row
  54.  
  55.  
  56. #define    kLeftArrowKey                0x7B
  57. #define    kRightArrowKey                0x7C
  58. #define    kDownArrowKey                0x7D
  59. #define    kUpArrowKey                    0x7E
  60.  
  61. #define    kLeftKeyPad                    0x56
  62. #define    kRightKeyPad                0x58
  63. #define    kDownKeyPad                    0x54
  64. #define    kUpKeyPad                    0x5B
  65.  
  66. #define kEscKey                        0x35
  67.  
  68.  
  69. enum tileIDs
  70. {
  71.     kFirstWallTile = 0,
  72.     kLastWallTile = 9,
  73.     kFirstSpikeTile,
  74.     kLastSpikeTile = kFirstSpikeTile + 15,
  75.     kBackgroundTile,
  76.     kFirstLeftFloorTile,
  77.     kLastLeftFloorTile = kFirstLeftFloorTile + 4,
  78.     kFirstRightFloorTile,
  79.     kLastRightFloorTile = kFirstRightFloorTile + 4,
  80.     kFirstChangingTile,
  81.     kLastChangingTile = kFirstChangingTile + 2,
  82.     kFirstBackgroundTile,
  83.     kLastBackgroundTile = kFirstBackgroundTile + 8,
  84.     kFirstExitTile,
  85.     kLastExitTile = kFirstExitTile + 2,
  86.     kMaxNumTiles
  87. };
  88.  
  89.  
  90.  
  91.  
  92. /***********/
  93. /* Globals */
  94. /***********/
  95.  
  96. SpriteWorldPtr        gSpriteWorldP;
  97. SpriteLayerPtr        gSpriteLayerP;
  98. TileMapStructPtr    gTileMapStructP;
  99. TileMapPtr            gTileMap;
  100. SpritePtr            gSimpleSpriteP;
  101. WindowPtr            gWindowP;
  102. short                gCurrentLevel = 128;
  103. Rect                gScreenMidRect, gSpriteInsetRect;
  104. Boolean                gSpriteCanJump, gSpriteIsJumping, gSpriteJumpStage;
  105. Boolean                gChangingFloorMode = true;
  106. Boolean                gDone = false;
  107. Boolean                gEscapeKey = false;
  108. Boolean                gSpikesAreUp = true;
  109. Boolean                gSpriteHitExit = false, gSpriteWasKilled = false;
  110.  
  111. struct moveKeys
  112. {
  113.     Boolean    up;
  114.     Boolean    right;
  115.     Boolean    down;
  116.     Boolean    left;
  117.     Boolean jump;
  118. } gKeys;
  119.  
  120.  
  121. ///--------------------------------------------------------------------------------------
  122. // Main
  123. ///--------------------------------------------------------------------------------------
  124.  
  125. void    main( void )
  126. {
  127.     Initialize(kNumberOfMoreMastersCalls);
  128.     
  129.     if (SWHasSystem7())
  130.     {
  131.         AllowKeyUpEvents();    // Part of SWGameUtils.c
  132.         SetCursor(*GetCursor(watchCursor));
  133.         
  134.         CreateWindow();
  135.         CreateSpriteWorld();
  136.         CreateBallSprite();
  137.         SWLockSpriteWorld(gSpriteWorldP);
  138.         
  139.         SetCursor(&qd.arrow);
  140.         HideCursor();
  141.         
  142.         SetUpAnimation();
  143.         RunAnimation();
  144.         ShutDown();
  145.         
  146.         RestoreEventMask();    // Call this after AllowKeyUpEvents
  147.     }
  148.     else
  149.     {
  150.         CantRunOnThisMachine();
  151.     }
  152. }
  153.  
  154.  
  155. ///--------------------------------------------------------------------------------------
  156. // CreateWindow
  157. ///--------------------------------------------------------------------------------------
  158.  
  159. void     CreateWindow( void )
  160. {
  161.     Rect        windRect;
  162.     RgnHandle    mBarUpdateRgn;
  163.     
  164.     gWindowP = GetNewCWindow(128, NULL, (WindowPtr)-1L);
  165.     
  166.     if (gWindowP == NULL)
  167.     {
  168.         CantFindResource();
  169.     }
  170.     else
  171.     {
  172.         if (kFullScreenWindow)
  173.         {
  174.             SizeWindow(gWindowP, SW_MIN(640, qd.screenBits.bounds.right), 
  175.                 SW_MIN(480, qd.screenBits.bounds.bottom), false);
  176.         }
  177.         else
  178.         {
  179.             SizeWindow(gWindowP, 512, 384, false);
  180.         }
  181.                 
  182.             // Center window in screen
  183.         windRect = gWindowP->portRect;
  184.         CenterRect(&windRect, &qd.screenBits.bounds);
  185.         
  186.             // Make sure window is aligned to long-word boundaries (for 8-bit mode)
  187.         windRect.left = windRect.left>>2<<2;
  188.         
  189.         MoveWindow(gWindowP, windRect.left, windRect.top, false);
  190.         ShowWindow(gWindowP);
  191.         SetPort(gWindowP);
  192.     }
  193.     
  194.     mBarUpdateRgn = SWHideMenuBar(gWindowP);
  195.     EraseRgn(mBarUpdateRgn);
  196. }
  197.  
  198.  
  199. ///--------------------------------------------------------------------------------------
  200. // CreateSpriteWorld
  201. ///--------------------------------------------------------------------------------------
  202.  
  203. void    CreateSpriteWorld( void )
  204. {
  205.     Rect        offscreenRect, worldRect;
  206.     OSErr        err;
  207.     
  208.     
  209.     err = SWEnterSpriteWorld();
  210.     FatalError(err);
  211.     
  212.     
  213.     worldRect = gWindowP->portRect;
  214.     InsetRect(&worldRect, kWorldRectInset, kWorldRectInset);
  215.     
  216.     
  217.         // Set size of offscreen area
  218.     offscreenRect = worldRect;
  219.     OffsetRect(&offscreenRect, -offscreenRect.left, -offscreenRect.top);
  220.     
  221.  
  222.         // Make offscreen area evenly divisible by tile width & height
  223.     if ( (offscreenRect.right/kTileWidth)*kTileWidth != offscreenRect.right)
  224.         offscreenRect.right = (offscreenRect.right/kTileWidth)*kTileWidth + kTileWidth;
  225.     
  226.     if ( (offscreenRect.bottom/kTileHeight)*kTileHeight != offscreenRect.bottom)
  227.         offscreenRect.bottom = (offscreenRect.bottom/kTileHeight)*kTileHeight + kTileHeight;
  228.     
  229.         // Create the scrolling sprite world
  230.     err = SWCreateSpriteWorldFromWindow(&gSpriteWorldP, (CWindowPtr)gWindowP, 
  231.             &worldRect, &offscreenRect, 0);
  232.     FatalError(err);
  233.     
  234.             // Create the sprite layer
  235.     err = SWCreateSpriteLayer(&gSpriteLayerP);
  236.     FatalError(err);
  237.     
  238.         // Add it to the world
  239.     SWAddSpriteLayer(gSpriteWorldP, gSpriteLayerP);
  240.     
  241.  
  242.     err = SWInitTiling(gSpriteWorldP, kTileHeight, kTileWidth, kMaxNumTiles);
  243.     FatalError(err);
  244.     
  245.     err = SWLoadTileMap(&gTileMapStructP, gCurrentLevel);
  246.     FatalError(err);
  247.  
  248.     SWInstallTileMap(gSpriteWorldP, gTileMapStructP, 0);
  249.     gTileMap = gTileMapStructP->tileMap;
  250.  
  251.         // Load first set of tiles
  252.     err = SWLoadTilesFromPictResource(
  253.         gSpriteWorldP, 
  254.         0,                        // startTileID 
  255.         kMaxNumTiles-1,            // endTileID
  256.         200,                    // pictResID
  257.         0,                        // maskResID
  258.         kNoMask,                // maskType
  259.         0,                        // horizBorderWidth
  260.         0);                        // vertBorderHeight
  261.     FatalError(err);
  262. }
  263.     
  264.  
  265. ///--------------------------------------------------------------------------------------
  266. // CreateBallSprite
  267. ///--------------------------------------------------------------------------------------
  268.  
  269. void    CreateBallSprite( void )
  270. {
  271.     OSErr    err;
  272.     
  273.         // Create the ball sprite    
  274.     err = SWCreateSpriteFromSinglePict(gSpriteWorldP, &gSimpleSpriteP, NULL,
  275.             128, 128, 40, 0, kFatMask);
  276.     FatalError(err);
  277.     
  278.         // Set up the ball sprite
  279.     SWLockSprite(gSimpleSpriteP);
  280.     SWAddSprite(gSpriteLayerP, gSimpleSpriteP);
  281.     SWSetSpriteMoveProc(gSimpleSpriteP, KeySpriteMoveProc);
  282.     SWSetSpriteMoveDelta(gSimpleSpriteP, 0, 0);
  283.     SWSetSpriteLocation(gSimpleSpriteP, kStartCol * kTileWidth, kStartRow * kTileHeight);
  284.     
  285.     
  286. //    SWSetSpriteLocation(gSimpleSpriteP, 51 * kTileWidth-5, 7 * kTileHeight);
  287.     
  288.  
  289.     
  290.         // Inset for left, top, right, and bottom of sprite when checking sprite with tiles
  291.     SetRect(&gSpriteInsetRect, 5, 4, 5, 0);
  292.     gSpriteCanJump = true;
  293.     gSpriteIsJumping = false;
  294.     gSpriteJumpStage = 0;
  295.     
  296.     
  297.         // Set the sprite's drawProc
  298.     if (gSpriteWorldP->pixelDepth == 8)        // If in 256 colors
  299.     {
  300.         if (kInterlacedMode)
  301.             SWSetSpriteDrawProc(gSimpleSpriteP, BP8BitInterlacedMaskDrawProc);
  302.         else
  303.             SWSetSpriteDrawProc(gSimpleSpriteP, BlitPixie8BitMaskDrawProc);
  304.     }
  305.     else if ( !(SW_PPC && gSpriteWorldP->pixelDepth < 8) )        // Not 256 colors
  306.     {
  307.             // Use interlaced drawProcs unless in B&W, where interlacing is ugly
  308.         if (kInterlacedMode && gSpriteWorldP->pixelDepth > 2)
  309.             SWSetSpriteDrawProc(gSimpleSpriteP, BPAllBitInterlacedMaskDrawProc);
  310.         else
  311.             SWSetSpriteDrawProc(gSimpleSpriteP, BlitPixieAllBitMaskDrawProc);
  312.     }
  313. }
  314.  
  315.  
  316. ///--------------------------------------------------------------------------------------
  317. // SetUpAnimation
  318. ///--------------------------------------------------------------------------------------
  319.  
  320. void    SetUpAnimation( void )
  321. {
  322.     Rect        moveBoundsRect;
  323.     
  324.     ResetKeys();
  325.     
  326.         // Set up data used by the SmoothScrollingWorldMoveProc
  327.     gScreenMidRect = gSimpleSpriteP->curFrameP->frameRect;
  328.     CenterRect( &gScreenMidRect, &gSpriteWorldP->backRect );
  329.     
  330.     SWSetSpriteWorldMaxFPS(gSpriteWorldP, kMaxFPS);
  331.     SWSyncSpriteWorldToVBL(gSpriteWorldP, kSyncToVBL);
  332.     SWSetCleanUpSpriteWorld(gSpriteWorldP);
  333.     
  334.         // movement boundary = size of tileMap
  335.     SetRect(&moveBoundsRect, 0, 0, 
  336.             gTileMapStructP->numCols * kTileWidth, 
  337.             gTileMapStructP->numRows * kTileHeight);
  338.     
  339.     SWSetTileChangeProc(gSpriteWorldP, TileChangeProc);
  340.     SWSetScrollingWorldMoveBounds(gSpriteWorldP, &moveBoundsRect);
  341.     SWSetScrollingWorldMoveProc(gSpriteWorldP, SmoothScrollingWorldMoveProc, gSimpleSpriteP);
  342.         
  343.         // Move visScrollRect to starting sprite position
  344.     SWMoveVisScrollRect(gSpriteWorldP, 
  345.         gSpriteWorldP->followSpriteP->destFrameRect.left - gSpriteWorldP->backRect.right/2,
  346.         gSpriteWorldP->followSpriteP->destFrameRect.top - gSpriteWorldP->backRect.bottom/2);
  347.  
  348.     if (gSpriteWorldP->pixelDepth == 8)        // If in 256 colors
  349.     {
  350.         if (kInterlacedMode)
  351.         {
  352.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BP8BitInterlacedRectDrawProc);
  353.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BP8BitInterlacedRectDrawProc);
  354.             SWSetPartialMaskDrawProc(gSpriteWorldP, BP8BitInterlacedPartialMaskDrawProc);
  355.             SWSetDoubleRectDrawProc(gSpriteWorldP, BP8BitInterlacedDoubleRectDrawProc);
  356.         }
  357.         else
  358.         {
  359.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixie8BitRectDrawProc);
  360.             SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixie8BitPartialMaskDrawProc);
  361.             SWSetDoubleRectDrawProc(gSpriteWorldP, BlitPixie8BitDoubleRectDrawProc);
  362.         }
  363.     }    // When running on PPC, we can't use the AllBit blitters in lower than 8-bit
  364.     else if ( !(SW_PPC && gSpriteWorldP->pixelDepth < 8) )    // Not 256 colors
  365.     {
  366.         if (kInterlacedMode && gSpriteWorldP->pixelDepth > 2)
  367.         {
  368.                 // Use interlaced drawProcs unless in B&W, where interlacing is ugly
  369.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BPAllBitInterlacedRectDrawProc);
  370.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BPAllBitInterlacedRectDrawProc);
  371.             SWSetPartialMaskDrawProc(gSpriteWorldP, BPAllBitInterlacedPartialMaskDrawProc);
  372.             if (gSpriteWorldP->pixelDepth == 16)
  373.                 SWSetDoubleRectDrawProc(gSpriteWorldP, BP16BitInterlacedDoubleRectDrawProc);
  374.         }
  375.         else
  376.         {
  377.             SWSetSpriteWorldOffscreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  378.             SWSetSpriteWorldScreenDrawProc(gSpriteWorldP, BlitPixieAllBitRectDrawProc);
  379.             SWSetPartialMaskDrawProc(gSpriteWorldP, BlitPixieAllBitPartialMaskDrawProc);
  380.             if (gSpriteWorldP->pixelDepth == 16)
  381.                 SWSetDoubleRectDrawProc(gSpriteWorldP, BlitPixie16BitDoubleRectDrawProc);
  382.         }
  383.     }
  384.     
  385.     
  386.         // Make sure CopyBits, if used, doesn't try to colorize things
  387.     SWSetPortToWindow(gSpriteWorldP);
  388.     ForeColor(blackColor);
  389.     BackColor(whiteColor);
  390.     
  391.     SWDrawTilesInBackground(gSpriteWorldP);
  392.     SWUpdateScrollingSpriteWorld(gSpriteWorldP, true);
  393. }
  394.  
  395.  
  396. ///--------------------------------------------------------------------------------------
  397. //  RunAnimation
  398. ///--------------------------------------------------------------------------------------
  399.  
  400. void    RunAnimation( void )
  401. {
  402.     unsigned long        frames;
  403.     
  404.     frames = 0;
  405.     StartTimer();
  406.     
  407.     gEscapeKey = false;
  408.     
  409.     FatalError( SWStickyError() ); // Make sure no errors got past us during setup
  410.  
  411.     while (!Button() && !gEscapeKey)
  412.     {
  413.         SWProcessScrollingSpriteWorld(gSpriteWorldP);
  414.         FatalError( SWStickyError() );     // Make sure no errors occurred during a MoveProc, etc.
  415.         SWAnimateScrollingSpriteWorld(gSpriteWorldP);
  416.         
  417.             // We call this in case the Control Strip or something changes our window's visRgn
  418.         KeepMenuBarHidden(gWindowP);
  419.         
  420.         if (gSpriteWorldP->frameHasOccurred)
  421.         {
  422.             frames++;
  423.             
  424.             if (gSpriteHitExit)
  425.                 AdvanceLevel();
  426.             else if (gSpriteWasKilled)
  427.                 KillSprite();
  428.         }
  429.     }
  430.     
  431.     
  432.     SWShowMenuBar(gWindowP);
  433.     ShowResults(frames);
  434. }
  435.  
  436.  
  437. ///--------------------------------------------------------------------------------------
  438. //  ShutDown (clean up and dispose of the SpriteWorld)
  439. ///--------------------------------------------------------------------------------------
  440.  
  441. void    ShutDown( void )
  442. {
  443.     SWDisposeSpriteWorld(&gSpriteWorldP);
  444.     SWExitSpriteWorld();
  445.     
  446.     FlushEvents(everyEvent, 0);
  447.     ShowCursor();
  448. }
  449.  
  450.  
  451. ///--------------------------------------------------------------------------------------
  452. //  KeySpriteMoveProc
  453. ///--------------------------------------------------------------------------------------
  454.  
  455. SW_FUNC void KeySpriteMoveProc(SpritePtr srcSpriteP)
  456. {
  457.     short        horizDir, tempHorizDelta;
  458.     Boolean        spriteIsOnGround = false;
  459.     
  460.     UpdateKeys();    // Put the latest key values in the keys structure
  461.     
  462.     
  463.         // See if the sprite is standing on a wall
  464.     spriteIsOnGround = false;
  465.     if ( ((srcSpriteP->destFrameRect.bottom - gSpriteInsetRect.bottom) / kTileHeight) *
  466.         kTileHeight == srcSpriteP->destFrameRect.bottom - gSpriteInsetRect.bottom )
  467.     {
  468.         gSpriteInsetRect.bottom--;    // Check one line lower than bottom of sprite
  469.         
  470.         if (SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  471.                 &gSpriteInsetRect, 0, 0, kFirstWallTile, kLastWallTile, false) ||
  472.             SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  473.                  &gSpriteInsetRect, 0, 0, kFirstLeftFloorTile, kLastChangingTile, false) )
  474.         {
  475.             spriteIsOnGround = true;
  476.         }
  477.         
  478.         gSpriteInsetRect.bottom++;    // Change rect to the way it was before
  479.     }
  480.     
  481.     
  482.     horizDir = (gKeys.right - gKeys.left);
  483.     
  484.     if (horizDir)        // Are we moving left or right?
  485.     {
  486.             // Did we change direction?
  487.         if ( (srcSpriteP->horizMoveDelta > 0 && horizDir < 0) ||
  488.              (srcSpriteP->horizMoveDelta < 0 && horizDir > 0) )
  489.         {
  490.             srcSpriteP->horizMoveDelta = 0;
  491.         }
  492.         
  493.             // Add speed to sprite
  494.         srcSpriteP->horizMoveDelta += horizDir * kWalkIncrease;
  495.         
  496.             // Keep from moving too fast
  497.         if (srcSpriteP->horizMoveDelta > kMaxWalkSpeed)
  498.             srcSpriteP->horizMoveDelta = kMaxWalkSpeed;
  499.         else if (srcSpriteP->horizMoveDelta < -kMaxWalkSpeed)
  500.             srcSpriteP->horizMoveDelta = -kMaxWalkSpeed;
  501.     }
  502.     else    // We're not moving, so slow down
  503.     {
  504.         if (srcSpriteP->horizMoveDelta > 0)
  505.             srcSpriteP->horizMoveDelta /= 2;
  506.         else if (srcSpriteP->horizMoveDelta < 0)
  507.             srcSpriteP->horizMoveDelta /= 2;
  508.     }    
  509.     
  510.         
  511.     if (gKeys.up && gSpriteIsJumping)    // Already jumping - continue going up
  512.     {
  513.         if (gSpriteJumpStage++ < kMaxSpriteJumpDistance)
  514.         {
  515.             srcSpriteP->vertMoveDelta = -kJumpSpeed + gSpriteJumpStage * 1.4;
  516.         }
  517.         else
  518.         {
  519.             gSpriteIsJumping = false;
  520.         }
  521.     }
  522.     else if (gKeys.up && gSpriteCanJump)    // Start new jump
  523.     {
  524.         if (spriteIsOnGround)
  525.         {
  526.             srcSpriteP->vertMoveDelta = -kJumpSpeed;
  527.             gSpriteIsJumping = true;
  528.             gSpriteCanJump = false;
  529.             gSpriteJumpStage = 0;
  530.         }
  531.     }
  532.     else    // Stopped jumping, so make it fall early
  533.     {
  534.         if (srcSpriteP->vertMoveDelta < 0)
  535.             srcSpriteP->vertMoveDelta += 3;
  536.         
  537.         gSpriteIsJumping = false;
  538.         
  539.         if (!gKeys.up && srcSpriteP->vertMoveDelta >= 0)
  540.             gSpriteCanJump = true;
  541.     }
  542.     
  543.         // Add gravity
  544.     srcSpriteP->vertMoveDelta += kGravitySpeed;
  545.         
  546.         // Keep ball from falling too fast
  547.     if (srcSpriteP->vertMoveDelta > kMaxFallSpeed)
  548.         srcSpriteP->vertMoveDelta = kMaxFallSpeed;
  549.  
  550.  
  551.  
  552.     srcSpriteP->destFrameRect.top += srcSpriteP->vertMoveDelta;
  553.     srcSpriteP->destFrameRect.bottom += srcSpriteP->vertMoveDelta;
  554.     tempHorizDelta = 0;
  555.     
  556.  
  557.         // Check for collisions with walls vertically
  558.     if (srcSpriteP->vertMoveDelta > 0)            // Moving down
  559.     {
  560.                 // Make sure sprite was above the tile before we fell through it. Otherwise,
  561.             // the sprite was never on top, and shouldn't be moved by the platform.
  562.         if ( ((srcSpriteP->oldFrameRect.bottom-1) / kTileHeight) < 
  563.              ((srcSpriteP->destFrameRect.bottom-1) / kTileHeight) )
  564.         {
  565.                 // Check for floors moving left
  566.             if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  567.                 &gSpriteInsetRect, 0, 0, kFirstLeftFloorTile, kFirstLeftFloorTile, false) )
  568.             {
  569.                 tempHorizDelta -= kMovingFloorForce;
  570.             }
  571.             
  572.                 // Check for floors moving right
  573.             if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  574.                  &gSpriteInsetRect, 0, 0, kFirstRightFloorTile, kFirstRightFloorTile, false) )
  575.             {
  576.                 tempHorizDelta += kMovingFloorForce;
  577.             }
  578.         }
  579.  
  580.             // Keep sprite from falling through moving floors
  581.         if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  582.              &gSpriteInsetRect, 0, 0, kFirstLeftFloorTile, kFirstRightFloorTile, true) )
  583.         {
  584.             srcSpriteP->vertMoveDelta = 0;
  585.         }
  586.             // Keep sprite from falling through a changing floor
  587.         else if ( gChangingFloorMode == true &&
  588.             SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  589.             &gSpriteInsetRect, 0, 0, kFirstChangingTile, kFirstChangingTile, true) )
  590.         {
  591.             srcSpriteP->vertMoveDelta = 0;
  592.         }
  593.         
  594.             // Make sure sprite doesn't fall through any walls
  595.         if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWBottomSide,
  596.             &gSpriteInsetRect, 0, 0, kFirstWallTile, kLastWallTile, true) )
  597.         {
  598.             srcSpriteP->vertMoveDelta = 0;
  599.         }
  600.     }
  601.     else if (srcSpriteP->vertMoveDelta < 0)        // Moving up
  602.     {
  603.         if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWTopSide,
  604.             &gSpriteInsetRect, 0, 0, kFirstWallTile, kLastWallTile, true) )
  605.         {
  606.             srcSpriteP->vertMoveDelta /= 2;
  607.             gSpriteIsJumping = false;
  608.         }
  609.     }
  610.     
  611.     
  612.     srcSpriteP->destFrameRect.right += srcSpriteP->horizMoveDelta + tempHorizDelta;
  613.     srcSpriteP->destFrameRect.left += srcSpriteP->horizMoveDelta + tempHorizDelta;
  614.     
  615.             // Check for collisions with walls horizontally
  616.     if (srcSpriteP->horizMoveDelta + tempHorizDelta > 0)        // Moving right
  617.     {
  618.         if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWRightSide,
  619.             &gSpriteInsetRect, 0, 0, kFirstWallTile, kLastWallTile, true) )
  620.         {
  621.             if (srcSpriteP->horizMoveDelta > 0)
  622.                 srcSpriteP->horizMoveDelta = 1;
  623.         }
  624.     }
  625.     else if (srcSpriteP->horizMoveDelta + tempHorizDelta < 0)    // Moving left
  626.     {
  627.         if ( SWCheckSpriteWithTiles(gSpriteWorldP, srcSpriteP, kSWLeftSide,
  628.             &gSpriteInsetRect, 0, 0, kFirstWallTile, kLastWallTile, true) )
  629.         {
  630.             if (srcSpriteP->horizMoveDelta < 0)
  631.                 srcSpriteP->horizMoveDelta = -1;
  632.         }
  633.     }
  634.     
  635.     srcSpriteP->needsToBeDrawn = true;
  636.     
  637.     
  638.         // See if sprite hit exit sign or spikes
  639.     if (SWCheckSpriteWithTiles(gSpriteWorldP, gSimpleSpriteP, kSWEntireSprite,
  640.          &gSpriteInsetRect, 0, 0, kFirstExitTile, kLastExitTile, false) )
  641.     {
  642.         gSpriteHitExit = true;
  643.     }
  644.     else if (gSpikesAreUp && SWCheckSpriteWithTiles(gSpriteWorldP, gSimpleSpriteP,
  645.              kSWEntireSprite, &gSpriteInsetRect, 0, 0, kFirstSpikeTile, kLastSpikeTile, false) )
  646.     {
  647.         gSpriteWasKilled = true;
  648.     }
  649. }
  650.  
  651.  
  652. ///--------------------------------------------------------------------------------------
  653. //  TileChangeProc
  654. ///--------------------------------------------------------------------------------------
  655.  
  656. SW_FUNC void TileChangeProc(SpriteWorldPtr spriteWorldP)
  657. {
  658.     short            curImage;
  659.     static short    wallDelay = 0, spikeTimer = 0, spikeDirection = 0, spikeDelay = 0;
  660.     static short    changingFloorDelay = 0, changingFloorWait = 0, exitDelay = 0;
  661.     static Boolean    spikesAreMoving = false;
  662.     static short    oldTicks = 0;
  663.     short            ticksPassed, ticks;
  664.     
  665.         // Initialize oldTicks the first time this function is called
  666.     if (oldTicks == 0)
  667.         oldTicks = TickCount();
  668.     
  669.     ticks = TickCount();
  670.     ticksPassed = ticks - oldTicks;        // Number of ticks passed since last call
  671.     oldTicks = ticks;
  672.     
  673.     changingFloorWait += ticksPassed;
  674.     if (changingFloorWait >= kChangingFloorWait)
  675.     {
  676.         changingFloorWait = 0;
  677.         if (gChangingFloorMode == true)
  678.         {
  679.             gChangingFloorMode = 0;
  680.             SWChangeTileImage(spriteWorldP, kFirstChangingTile, kBackgroundTile);
  681.         }
  682.         else
  683.         {
  684.             gChangingFloorMode = 1;
  685.             SWChangeTileImage(spriteWorldP, kFirstChangingTile, kFirstChangingTile);
  686.         }
  687.     }
  688.     
  689.         // Change the changing floor
  690.     if (gChangingFloorMode == true)
  691.     {
  692.         changingFloorDelay += ticksPassed;
  693.         if (changingFloorDelay >= kChangingFloorSpeed)
  694.         {
  695.             curImage = spriteWorldP->curTileImage[kFirstChangingTile];
  696.             if (curImage < kLastChangingTile)
  697.                 curImage++;
  698.             else
  699.                 curImage = kFirstChangingTile;
  700.             
  701.             SWChangeTileImage(spriteWorldP, kFirstChangingTile, curImage);
  702.             changingFloorDelay = 0;
  703.         }
  704.     }
  705.     
  706.         // Change the moving floors
  707.     wallDelay += ticksPassed;
  708.     if (wallDelay >= kMovingFloorSpeed)
  709.     {
  710.             // Move the left wall
  711.         curImage = spriteWorldP->curTileImage[kFirstLeftFloorTile];
  712.         if (curImage < kLastLeftFloorTile)
  713.             curImage++;
  714.         else
  715.             curImage = kFirstLeftFloorTile;
  716.         
  717.         SWChangeTileImage(spriteWorldP, kFirstLeftFloorTile, curImage);
  718.         
  719.             // Move the right wall
  720.         curImage = spriteWorldP->curTileImage[kFirstRightFloorTile];
  721.         if (curImage < kLastRightFloorTile)
  722.             curImage++;
  723.         else
  724.             curImage = kFirstRightFloorTile;
  725.         
  726.         SWChangeTileImage(spriteWorldP, kFirstRightFloorTile, curImage);
  727.         
  728.         wallDelay = 0;
  729.     }
  730.     
  731.     
  732.         // Change the spikes
  733.     if (spikesAreMoving)
  734.     {
  735.         spikeDelay += ticksPassed;
  736.         if (spikeDelay >= kSpikeSpeed)
  737.         {
  738.             curImage = spriteWorldP->curTileImage[kFirstSpikeTile];
  739.             curImage += spikeDirection;
  740.             if (curImage == kLastSpikeTile+1 || curImage == kFirstSpikeTile)
  741.             {        
  742.                 spikesAreMoving = false;
  743.                 if (spikeDirection > 0)
  744.                     spikeDirection = -1;
  745.                 else
  746.                     spikeDirection = 1;
  747.             }
  748.             
  749.                 // Determine whether the current spike position can kill the sprite
  750.             if (curImage > kFirstSpikeTile + 7)
  751.                 gSpikesAreUp = false;
  752.             else
  753.                 gSpikesAreUp = true;
  754.             
  755.             SWChangeTileImage(spriteWorldP, kFirstSpikeTile, curImage);
  756.             spikeDelay = 0;
  757.         }
  758.     }
  759.     else
  760.     {
  761.         spikeTimer += ticksPassed;
  762.         if (spikeTimer > kSpikeChangeDelay)
  763.         {
  764.             spikeTimer = 0;
  765.             spikesAreMoving = true;
  766.         }
  767.     }
  768.     
  769.  
  770.         // Animate the exit sign
  771.     exitDelay += ticksPassed;
  772.     if (exitDelay >= kExitSignSpeed)
  773.     {
  774.         curImage = spriteWorldP->curTileImage[kFirstExitTile];
  775.         if (curImage < kLastExitTile)
  776.             curImage++;
  777.         else
  778.             curImage = kFirstExitTile;
  779.         
  780.         SWChangeTileImage(spriteWorldP, kFirstExitTile, curImage);
  781.         exitDelay = 0;
  782.     }
  783. }
  784.  
  785.  
  786. ///--------------------------------------------------------------------------------------
  787. //  SmoothScrollingWorldMoveProc - our scrolling WorldMoveProc
  788. ///--------------------------------------------------------------------------------------
  789.  
  790. SW_FUNC void SmoothScrollingWorldMoveProc(
  791.     SpriteWorldPtr spriteWorldP,
  792.     SpritePtr followSpriteP)
  793. {    
  794.     short    screenMidRectTop, screenMidRectLeft;
  795.     
  796.     screenMidRectTop = gScreenMidRect.top + spriteWorldP->visScrollRect.top;
  797.     screenMidRectLeft = gScreenMidRect.left + spriteWorldP->visScrollRect.left;
  798.     
  799.     
  800.     spriteWorldP->horizScrollDelta = (kMaxWalkSpeed * 
  801.         (followSpriteP->destFrameRect.left - screenMidRectLeft) ) / kSpriteMoveDistance;
  802.     
  803.     spriteWorldP->vertScrollDelta = (kMaxFallSpeed * 
  804.         (followSpriteP->destFrameRect.top - screenMidRectTop) ) / kSpriteMoveDistance;
  805.     
  806.     if (kInterlacedMode)
  807.         spriteWorldP->vertScrollDelta = spriteWorldP->vertScrollDelta>>1<<1;
  808. }
  809.  
  810.  
  811. ///--------------------------------------------------------------------------------------
  812. //  UpdateKeys (Put the latest key values in the keys structure)
  813. ///--------------------------------------------------------------------------------------
  814.  
  815. void    UpdateKeys( void )
  816. {
  817.     EventRecord        event;
  818.     short            theKey;
  819.     Boolean            isDown;
  820.     
  821.     
  822.     while ( GetOSEvent( (keyUpMask | keyDownMask), &event ) )
  823.     {
  824.         theKey = (event.message & keyCodeMask) >> 8;
  825.         isDown = (event.what != keyUp);
  826.         
  827.         if ( (theKey == kLeftArrowKey) || (theKey == kLeftKeyPad) )
  828.             gKeys.left = isDown;
  829.         else if ( (theKey == kRightArrowKey) || (theKey == kRightKeyPad) )
  830.             gKeys.right = isDown;
  831.         else if ( (theKey == kDownArrowKey) || (theKey == kDownKeyPad) )
  832.             gKeys.down = isDown;
  833.         else if ( (theKey == kUpArrowKey) || (theKey == kUpKeyPad) )
  834.             gKeys.up = isDown;
  835.         else if (theKey == kEscKey)
  836.             gEscapeKey = isDown;
  837.     }
  838. }
  839.  
  840.  
  841. ///--------------------------------------------------------------------------------------
  842. //  ResetKeys (Called when setting up a new game)
  843. ///--------------------------------------------------------------------------------------
  844.  
  845. void    ResetKeys( void )
  846. {
  847.     gKeys.left = 0;
  848.     gKeys.right = 0;
  849.     gKeys.down = 0;
  850.     gKeys.up = 0;
  851.     gEscapeKey = 0;
  852. }
  853.  
  854.  
  855. ///--------------------------------------------------------------------------------------
  856. //  AdvanceLevel
  857. ///--------------------------------------------------------------------------------------
  858.  
  859. void    AdvanceLevel( void )
  860. {
  861.     Rect            moveBoundsRect;
  862.     unsigned long    junkTime;
  863.     OSErr            err;
  864.     
  865.     gCurrentLevel++;
  866.     gSpriteHitExit = false;
  867.     
  868.     SWDisposeTileMap(&gTileMapStructP);
  869.     err = SWLoadTileMap(&gTileMapStructP, gCurrentLevel);
  870.     if (err)
  871.     {
  872.         gCurrentLevel = 128;
  873.         SWClearStickyError();    // Clear the sticky error that was set when the level didn't load.
  874.         err = SWLoadTileMap(&gTileMapStructP, gCurrentLevel);
  875.         FatalError(err);
  876.     }
  877.     
  878.     gTileMap = gTileMapStructP->tileMap;
  879.     SWInstallTileMap(gSpriteWorldP, gTileMapStructP, 0);
  880.     
  881.         // Reset scrolling moveBounds for new TileMap
  882.     SetRect(&moveBoundsRect, 0, 0, 
  883.         gTileMapStructP->numCols * kTileWidth, 
  884.         gTileMapStructP->numRows * kTileHeight);
  885.     SWSetScrollingWorldMoveBounds(gSpriteWorldP, &moveBoundsRect);
  886.     
  887.     
  888.     ResetSprite();
  889.     Delay(30, &junkTime);
  890.     
  891.     SWDrawTilesInBackground(gSpriteWorldP);
  892.     SWUpdateSpriteWorld(gSpriteWorldP, false);
  893. }
  894.  
  895.  
  896. ///--------------------------------------------------------------------------------------
  897. //  KillSprite
  898. ///--------------------------------------------------------------------------------------
  899.  
  900. void    KillSprite( void )
  901. {
  902.     unsigned long    dummyTicks;
  903.     
  904.     gSpriteWasKilled = false;
  905.     SWSetSpriteFrameTime(gSimpleSpriteP, 1000/15);
  906.     SWSetSpriteFrameAdvance(gSimpleSpriteP, 1);
  907.     SWSetSpriteMoveProc(gSimpleSpriteP, NULL);
  908.     
  909.     do
  910.     {        // Run the "popped ball" animation
  911.         SWProcessScrollingSpriteWorld(gSpriteWorldP);
  912.         SWAnimateScrollingSpriteWorld(gSpriteWorldP);
  913.     } while (gSimpleSpriteP->curFrameIndex < gSimpleSpriteP->maxFrames-1 && !Button());
  914.     
  915.     Delay(23, &dummyTicks);
  916.     ResetSprite();
  917. }
  918.  
  919.  
  920. ///--------------------------------------------------------------------------------------
  921. //  ResetSprite
  922. ///--------------------------------------------------------------------------------------
  923.  
  924. void    ResetSprite( void )
  925. {
  926.     SWSetSpriteMoveDelta(gSimpleSpriteP, 0, 0);
  927.     SWMoveSprite(gSimpleSpriteP, kStartCol * kTileWidth, kStartRow * kTileHeight);
  928.     SWMoveVisScrollRect(gSpriteWorldP, 0, 0);
  929.     
  930.     SWSetSpriteFrameAdvance(gSimpleSpriteP, 0);
  931.     SWSetSpriteMoveProc(gSimpleSpriteP, KeySpriteMoveProc);
  932.     SWSetCurrentFrameIndex(gSimpleSpriteP, 0);
  933.     
  934.     gSpriteCanJump = false;
  935.     gSpriteIsJumping = false;
  936.     gSpriteJumpStage = 0;
  937. }
  938.